home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / progutil / iostream.zoo / src / vbprintf.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-22  |  19.9 KB  |  865 lines

  1. /*
  2.  * Copyright (c) 1990 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18.  
  19. #if defined(LIBC_SCCS) && !defined(lint)
  20. static char sccsid[] = "%W% (Berkeley) %G%";
  21. #endif /* LIBC_SCCS and not lint */
  22.  
  23. /*
  24.  * Actual printf innards.
  25.  *
  26.  * This code is large and complicated...
  27.  */
  28.  
  29. #include <sys/types.h>
  30. #include "ioprivat.h"
  31. #include <string.h>
  32. #if __STDC__
  33. #include <stdarg.h>
  34. #else
  35. #include <varargs.h>
  36. #endif
  37. //#include "local.h"
  38. #include "fvwrite.h"
  39.  
  40. /*
  41.  * Define FLOATING_POINT to get floating point.
  42.  */
  43. #ifndef    NO_FLOATING_POINT
  44. #define    FLOATING_POINT
  45. #endif
  46.  
  47. extern int __sbvwrite(register streambuf *fp, register struct __suio *uio);
  48.  
  49. /* end of configuration stuff */
  50.  
  51.  
  52. /*
  53.  * Flush out all the vectors defined by the given uio,
  54.  * then reset it so that it can be reused.
  55.  */
  56. static int __sbprint(streambuf *sb, register struct __suio *uio)
  57. {
  58.     register int err;
  59.  
  60.     if (uio->uio_resid == 0) {
  61.         uio->uio_iovcnt = 0;
  62.         return (0);
  63.     }
  64.     err = __sbvwrite(sb, uio);
  65.     uio->uio_resid = 0;
  66.     uio->uio_iovcnt = 0;
  67.     return (err);
  68. }
  69.  
  70. /*
  71.  * Helper function for `fprintf to unbuffered unix file': creates a
  72.  * temporary buffer.  We only work on write-only files; this avoids
  73.  * worries about ungetc buffers and so forth.
  74.  */
  75. #if 0
  76. /* static */
  77. int __sbprintf(register FILE *fp, char const *fmt, va_list ap)
  78. {
  79.     int ret;
  80.     FILE fake;
  81.     unsigned char buf[BUFSIZ];
  82.  
  83.     /* copy the important variables */
  84.     fake._flags = fp->_flags & ~__SNBF;
  85.     fake._file = fp->_file;
  86.     fake._cookie = fp->_cookie;
  87.     fake._write = fp->_write;
  88.  
  89.     /* set up the buffer */
  90.     fake._bf._base = fake._p = buf;
  91.     fake._bf._size = fake._w = sizeof(buf);
  92.     fake._lbfsize = 0;    /* not actually used, but Just In Case */
  93.  
  94.     /* do the work, then copy any error status */
  95.     ret = vfprintf(&fake, fmt, ap);
  96.     if (ret >= 0 && fflush(&fake))
  97.         ret = EOF;
  98.     if (fake._flags & __SERR)
  99.         fp->_flags |= __SERR;
  100.     return (ret);
  101. }
  102. #endif
  103.  
  104.  
  105. #ifdef FLOATING_POINT
  106.  
  107. #include "floatio.h"
  108. #define    BUF        (MAXEXP+MAXFRACT+1)    /* + decimal point */
  109. #define    DEFPREC        6
  110. extern "C" double modf(double, double*);
  111.  
  112. #else /* no FLOATING_POINT */
  113.  
  114. #define    BUF        40
  115.  
  116. #endif /* FLOATING_POINT */
  117.  
  118.  
  119. /*
  120.  * Macros for converting digits to letters and vice versa
  121.  */
  122. #define    to_digit(c)    ((c) - '0')
  123. #define is_digit(c)    ((unsigned)to_digit(c) <= 9)
  124. #define    to_char(n)    ((n) + '0')
  125.  
  126. /*
  127.  * Flags used during conversion.
  128.  */
  129. #define    LONGINT        0x01        /* long integer */
  130. #define    LONGDBL        0x02        /* long double; unimplemented */
  131. #define    SHORTINT    0x04        /* short integer */
  132. #define    ALT        0x08        /* alternate form */
  133. #define    LADJUST        0x10        /* left adjustment */
  134. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  135. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  136.  
  137. int __vsbprintf(streambuf *sb, char const *fmt0, va_list ap)
  138. {
  139.     register char *fmt;    /* format string */
  140.     register int ch;    /* character from fmt */
  141.     register int n;        /* handy integer (short term usage) */
  142.     register char *cp;    /* handy char pointer (short term usage) */
  143.     register struct __siov *iovp;/* for PRINT macro */
  144.     register int flags;    /* flags as above */
  145.     int ret;        /* return value accumulator */
  146.     int width;        /* width from format (%8d), or 0 */
  147.     int prec;        /* precision from format (%.3d), or -1 */
  148.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  149. #ifdef FLOATING_POINT
  150.     char softsign;        /* temporary negative sign for floats */
  151.     double _double;        /* double precision arguments %[eEfgG] */
  152.     int fpprec;        /* `extra' floating precision in [eEfgG] */
  153. #endif
  154.     unsigned long _ulong;    /* integer arguments %[diouxX] */
  155.     enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
  156.     int dprec;        /* a copy of prec if [diouxX], 0 otherwise */
  157.     int fieldsz;        /* field size expanded by sign, etc */
  158.     int realsz;        /* field size expanded by dprec */
  159.     int size;        /* size of converted field or string */
  160.     char *xdigs;        /* digits for [xX] conversion */
  161. #define NIOV 8
  162.     struct __suio uio;    /* output information: summary */
  163.     struct __siov iov[NIOV];/* ... and individual io vectors */
  164.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  165.     char ox[2];        /* space for 0x hex-prefix */
  166.  
  167.     /*
  168.      * Choose PADSIZE to trade efficiency vs size.  If larger
  169.      * printf fields occur frequently, increase PADSIZE (and make
  170.      * the initialisers below longer).
  171.      */
  172. #define    PADSIZE    16        /* pad chunk size */
  173.     static char const blanks[PADSIZE] =
  174.      {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
  175.     static char const zeroes[PADSIZE] =
  176.      {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
  177.  
  178.     /*
  179.      * BEWARE, these `goto error' on error, and PAD uses `n'.
  180.      */
  181. #if 0
  182. #define    PRINT(ptr, len) sb->sputn(ptr, len)
  183. #define    FLUSH() { }
  184. #else
  185. #define    PRINT(ptr, len) { \
  186.     iovp->iov_base = (ptr); \
  187.     iovp->iov_len = (len); \
  188.     uio.uio_resid += (len); \
  189.     iovp++; \
  190.     if (++uio.uio_iovcnt >= NIOV) { \
  191.         if (__sbprint(sb, &uio)) \
  192.             goto error; \
  193.         iovp = iov; \
  194.     } \
  195. }
  196. #define    FLUSH() { \
  197.     if (uio.uio_resid && __sbprint(sb, &uio)) \
  198.         goto error; \
  199.     uio.uio_iovcnt = 0; \
  200.     iovp = iov; \
  201. }
  202. #endif
  203. #define    PAD(howmany, with) { \
  204.     if ((n = (howmany)) > 0) { \
  205.         while (n > PADSIZE) { \
  206.             PRINT(with, PADSIZE); \
  207.             n -= PADSIZE; \
  208.         } \
  209.         PRINT(with, n); \
  210.     } \
  211. }
  212.  
  213.     /*
  214.      * To extend shorts properly, we need both signed and unsigned
  215.      * argument extraction methods.
  216.      */
  217. #define    SARG() \
  218.     (flags&LONGINT ? va_arg(ap, long) : \
  219.         flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
  220.         (long)va_arg(ap, int))
  221. #define    UARG() \
  222.     (flags&LONGINT ? va_arg(ap, unsigned long) : \
  223.         flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \
  224.         (unsigned long)va_arg(ap, unsigned int))
  225.  
  226.     /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
  227.     if (!(sb->_flags & _S_CAN_WRITE))
  228.         return (EOF);
  229. #if 0
  230.     /* optimise fprintf(stderr) (and other unbuffered Unix files) */
  231. <    if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
  232.         fp->_file >= 0)
  233.         return (__sbprintf(fp, fmt0, ap));
  234. #endif
  235.  
  236.     fmt = (char *)fmt0;
  237.     uio.uio_iov = iovp = iov;
  238.     uio.uio_resid = 0;
  239.     uio.uio_iovcnt = 0;
  240.     ret = 0;
  241.  
  242.     /*
  243.      * Scan the format for conversions (`%' character).
  244.      */
  245.     for (;;) {
  246.         for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
  247.             /* void */;
  248.         if ((n = fmt - cp) != 0) {
  249.             PRINT(cp, n);
  250.             ret += n;
  251.         }
  252.         if (ch == '\0')
  253.             goto done;
  254.         fmt++;        /* skip over '%' */
  255.  
  256.         flags = 0;
  257.         dprec = 0;
  258. #ifdef FLOATING_POINT
  259.         fpprec = 0;
  260. #endif
  261.         width = 0;
  262.         prec = -1;
  263.         sign = '\0';
  264.  
  265. rflag:        ch = *fmt++;
  266. reswitch:    switch (ch) {
  267.         case ' ':
  268.             /*
  269.              * ``If the space and + flags both appear, the space
  270.              * flag will be ignored.''
  271.              *    -- ANSI X3J11
  272.              */
  273.             if (!sign)
  274.                 sign = ' ';
  275.             goto rflag;
  276.         case '#':
  277.             flags |= ALT;
  278.             goto rflag;
  279.         case '*':
  280.             /*
  281.              * ``A negative field width argument is taken as a
  282.              * - flag followed by a positive field width.''
  283.              *    -- ANSI X3J11
  284.              * They don't exclude field widths read from args.
  285.              */
  286.             if ((width = va_arg(ap, int)) >= 0)
  287.                 goto rflag;
  288.             width = -width;
  289.             /* FALLTHROUGH */
  290.         case '-':
  291.             flags |= LADJUST;
  292.             goto rflag;
  293.         case '+':
  294.             sign = '+';
  295.             goto rflag;
  296.         case '.':
  297.             if ((ch = *fmt++) == '*') {
  298.                 n = va_arg(ap, int);
  299.                 prec = n < 0 ? -1 : n;
  300.                 goto rflag;
  301.             }
  302.             n = 0;
  303.             while (is_digit(ch)) {
  304.                 n = 10 * n + to_digit(ch);
  305.                 ch = *fmt++;
  306.             }
  307.             prec = n < 0 ? -1 : n;
  308.             goto reswitch;
  309.         case '0':
  310.             /*
  311.              * ``Note that 0 is taken as a flag, not as the
  312.              * beginning of a field width.''
  313.              *    -- ANSI X3J11
  314.              */
  315.             flags |= ZEROPAD;
  316.             goto rflag;
  317.         case '1': case '2': case '3': case '4':
  318.         case '5': case '6': case '7': case '8': case '9':
  319.             n = 0;
  320.             do {
  321.                 n = 10 * n + to_digit(ch);
  322.                 ch = *fmt++;
  323.             } while (is_digit(ch));
  324.             width = n;
  325.             goto reswitch;
  326. #ifdef FLOATING_POINT
  327.         case 'L':
  328.             flags |= LONGDBL;
  329.             goto rflag;
  330. #endif
  331.         case 'h':
  332.             flags |= SHORTINT;
  333.             goto rflag;
  334.         case 'l':
  335.             flags |= LONGINT;
  336.             goto rflag;
  337.         case 'c':
  338.             *(cp = buf) = va_arg(ap, int);
  339.             size = 1;
  340.             sign = '\0';
  341.             break;
  342.         case 'D':
  343.             flags |= LONGINT;
  344.             /*FALLTHROUGH*/
  345.         case 'd':
  346.         case 'i':
  347.             _ulong = SARG();
  348.             if ((long)_ulong < 0) {
  349.                 _ulong = -_ulong;
  350.                 sign = '-';
  351.             }
  352.             base = DEC;
  353.             goto number;
  354. #ifdef FLOATING_POINT
  355.         case 'e':
  356.         case 'E':
  357.         case 'f':
  358.         case 'g':
  359.         case 'G':
  360.             _double = va_arg(ap, double);
  361.             /*
  362.              * don't do unrealistic precision; just pad it with
  363.              * zeroes later, so buffer size stays rational.
  364.              */
  365.             if (prec > MAXFRACT) {
  366.                 if ((ch != 'g' && ch != 'G') || (flags&ALT))
  367.                     fpprec = prec - MAXFRACT;
  368.                 prec = MAXFRACT;
  369.             } else if (prec == -1)
  370.                 prec = DEFPREC;
  371.             // __cvt_double may have to round up before the
  372.             // "start" of its buffer, i.e.
  373.             // ``intf("%.2f", (double)9.999);'';
  374.             // if the first character is still NUL, it did.
  375.             // softsign avoids negative 0 if _double < 0 but
  376.             // no significant digits will be shown.
  377.             cp = buf;
  378.             *cp = '\0';
  379.             size = __cvt_double(_double, prec, flags, &softsign,
  380.                         ch, cp, buf + sizeof(buf));
  381.             if (softsign)
  382.                 sign = '-';
  383.             if (*cp == '\0')
  384.                 cp++;
  385.             break;
  386. #endif /* FLOATING_POINT */
  387.         case 'n':
  388.             if (flags & LONGINT)
  389.                 *va_arg(ap, long *) = ret;
  390.             else if (flags & SHORTINT)
  391.                 *va_arg(ap, short *) = ret;
  392.             else
  393.                 *va_arg(ap, int *) = ret;
  394.             continue;    /* no output */
  395.         case 'O':
  396.             flags |= LONGINT;
  397.             /*FALLTHROUGH*/
  398.         case 'o':
  399.             _ulong = UARG();
  400.             base = OCT;
  401.             goto nosign;
  402.         case 'p':
  403.             /*
  404.              * ``The argument shall be a pointer to void.  The
  405.              * value of the pointer is converted to a sequence
  406.              * of printable characters, in an implementation-
  407.              * defined manner.''
  408.              *    -- ANSI X3J11
  409.              */
  410.             /* NOSTRICT */
  411.             _ulong = (unsigned long)va_arg(ap, void *);
  412.             base = HEX;
  413.             xdigs = "0123456789abcdef";
  414.             flags |= HEXPREFIX;
  415.             ch = 'x';
  416.             goto nosign;
  417.         case 's':
  418.             if ((cp = va_arg(ap, char *)) == NULL)
  419.                 cp = "(null)";
  420.             if (prec >= 0) {
  421.                 /*
  422.                  * can't use strlen; can only look for the
  423.                  * NUL in the first `prec' characters, and
  424.                  * strlen() will go further.
  425.                  */
  426.                 char *p = memchr(cp, 0, prec);
  427.  
  428.                 if (p != NULL) {
  429.                     size = p - cp;
  430.                     if (size > prec)
  431.                         size = prec;
  432.                 } else
  433.                     size = prec;
  434.             } else
  435.                 size = strlen(cp);
  436.             sign = '\0';
  437.             break;
  438.         case 'U':
  439.             flags |= LONGINT;
  440.             /*FALLTHROUGH*/
  441.         case 'u':
  442.             _ulong = UARG();
  443.             base = DEC;
  444.             goto nosign;
  445.         case 'X':
  446.             xdigs = "0123456789ABCDEF";
  447.             goto hex;
  448.         case 'x':
  449.             xdigs = "0123456789abcdef";
  450. hex:            _ulong = UARG();
  451.             base = HEX;
  452.             /* leading 0x/X only if non-zero */
  453.             if (flags & ALT && _ulong != 0)
  454.                 flags |= HEXPREFIX;
  455.  
  456.             /* unsigned conversions */
  457. nosign:            sign = '\0';
  458.             /*
  459.              * ``... diouXx conversions ... if a precision is
  460.              * specified, the 0 flag will be ignored.''
  461.              *    -- ANSI X3J11
  462.              */
  463. number:            if ((dprec = prec) >= 0)
  464.                 flags &= ~ZEROPAD;
  465.  
  466.             /*
  467.              * ``The result of converting a zero value with an
  468.              * explicit precision of zero is no characters.''
  469.              *    -- ANSI X3J11
  470.              */
  471.             cp = buf + BUF;
  472.             if (_ulong != 0 || prec != 0) {
  473.                 /*
  474.                  * unsigned mod is hard, and unsigned mod
  475.                  * by a constant is easier than that by
  476.                  * a variable; hence this switch.
  477.                  */
  478.                 switch (base) {
  479.                 case OCT:
  480.                     do {
  481.                         *--cp = to_char(_ulong & 7);
  482.                         _ulong >>= 3;
  483.                     } while (_ulong);
  484.                     /* handle octal leading 0 */
  485.                     if (flags & ALT && *cp != '0')
  486.                         *--cp = '0';
  487.                     break;
  488.  
  489.                 case DEC:
  490.                     /* many numbers are 1 digit */
  491.                     while (_ulong >= 10) {
  492.                         *--cp = to_char(_ulong % 10);
  493.                         _ulong /= 10;
  494.                     }
  495.                     *--cp = to_char(_ulong);
  496.                     break;
  497.  
  498.                 case HEX:
  499.                     do {
  500.                         *--cp = xdigs[_ulong & 15];
  501.                         _ulong >>= 4;
  502.                     } while (_ulong);
  503.                     break;
  504.  
  505.                 default:
  506.                     cp = "bug in __vsbprintf: bad base";
  507.                     goto skipsize;
  508.                 }
  509.             }
  510.             size = buf + BUF - cp;
  511.         skipsize:
  512.             break;
  513.         default:    /* "%?" prints ?, unless ? is NUL */
  514.             if (ch == '\0')
  515.                 goto done;
  516.             /* pretend it was %c with argument ch */
  517.             cp = buf;
  518.             *cp = ch;
  519.             size = 1;
  520.             sign = '\0';
  521.             break;
  522.         }
  523.  
  524.         /*
  525.          * All reasonable formats wind up here.  At this point,
  526.          * `cp' points to a string which (if not flags&LADJUST)
  527.          * should be padded out to `width' places.  If
  528.          * flags&ZEROPAD, it should first be prefixed by any
  529.          * sign or other prefix; otherwise, it should be blank
  530.          * padded before the prefix is emitted.  After any
  531.          * left-hand padding and prefixing, emit zeroes
  532.          * required by a decimal [diouxX] precision, then print
  533.          * the string proper, then emit zeroes required by any
  534.          * leftover floating precision; finally, if LADJUST,
  535.          * pad with blanks.
  536.          */
  537.  
  538.         /*
  539.          * compute actual size, so we know how much to pad.
  540.          * fieldsz excludes decimal prec; realsz includes it
  541.          */
  542. #ifdef FLOATING_POINT
  543.         fieldsz = size + fpprec;
  544. #else
  545.         fieldsz = size;
  546. #endif
  547.         if (sign)
  548.             fieldsz++;
  549.         else if (flags & HEXPREFIX)
  550.             fieldsz += 2;
  551.         realsz = dprec > fieldsz ? dprec : fieldsz;
  552.  
  553.         /* right-adjusting blank padding */
  554.         if ((flags & (LADJUST|ZEROPAD)) == 0)
  555.             PAD(width - realsz, blanks);
  556.  
  557.         /* prefix */
  558.         if (sign) {
  559.             PRINT(&sign, 1);
  560.         } else if (flags & HEXPREFIX) {
  561.             ox[0] = '0';
  562.             ox[1] = ch;
  563.             PRINT(ox, 2);
  564.         }
  565.  
  566.         /* right-adjusting zero padding */
  567.         if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  568.             PAD(width - realsz, zeroes);
  569.  
  570.         /* leading zeroes from decimal precision */
  571.         PAD(dprec - fieldsz, zeroes);
  572.  
  573.         /* the string or number proper */
  574.         PRINT(cp, size);
  575.  
  576. #ifdef FLOATING_POINT
  577.         /* trailing f.p. zeroes */
  578.         PAD(fpprec, zeroes);
  579. #endif
  580.  
  581.         /* left-adjusting padding (always blank) */
  582.         if (flags & LADJUST)
  583.             PAD(width - realsz, blanks);
  584.  
  585.         /* finally, adjust ret */
  586.         ret += width > realsz ? width : realsz;
  587.  
  588.         FLUSH();    /* copy out the I/O vectors */
  589.     }
  590. done:
  591.     FLUSH();
  592.     return ret;
  593. error:
  594.     return EOF;
  595.     /* NOTREACHED */
  596. }
  597.  
  598. #ifdef FLOATING_POINT
  599.  
  600. static char *exponent(register char *p, register int exp, int fmtch)
  601. {
  602.     register char *t;
  603.     char expbuf[MAXEXP];
  604.  
  605.     *p++ = fmtch;
  606.     if (exp < 0) {
  607.         exp = -exp;
  608.         *p++ = '-';
  609.     }
  610.     else
  611.         *p++ = '+';
  612.     t = expbuf + MAXEXP;
  613.     if (exp > 9) {
  614.         do {
  615.             *--t = to_char(exp % 10);
  616.         } while ((exp /= 10) > 9);
  617.         *--t = to_char(exp);
  618.         for (; t < expbuf + MAXEXP; *p++ = *t++);
  619.     }
  620.     else {
  621.         *p++ = '0';
  622.         *p++ = to_char(exp);
  623.     }
  624.     return (p);
  625. }
  626.  
  627. static char * round(double fract, int *exp,
  628.             register char *start, register char *end,
  629.             char ch, char *signp)
  630. {
  631.     double tmp;
  632.  
  633.     if (fract)
  634.     (void)modf(fract * 10, &tmp);
  635.     else
  636.         tmp = to_digit(ch);
  637.     if (tmp > 4)
  638.         for (;; --end) {
  639.             if (*end == '.')
  640.                 --end;
  641.             if (++*end <= '9')
  642.                 break;
  643.             *end = '0';
  644.             if (end == start) {
  645.                 if (exp) {    /* e/E; increment exponent */
  646.                     *end = '1';
  647.                     ++*exp;
  648.                 }
  649.                 else {        /* f; add extra digit */
  650.                 *--end = '1';
  651.                 --start;
  652.                 }
  653.                 break;
  654.             }
  655.         }
  656.     /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  657.     else if (*signp == '-')
  658.         for (;; --end) {
  659.             if (*end == '.')
  660.                 --end;
  661.             if (*end != '0')
  662.                 break;
  663.             if (end == start)
  664.                 *signp = 0;
  665.         }
  666.     return (start);
  667. }
  668.  
  669. int __cvt_double(double number, register int prec, int flags, char *signp,
  670.          int fmtch, char *startp, char *endp)
  671. {
  672.     register char *p, *t;
  673.     register double fract;
  674.     int dotrim, expcnt, gformat;
  675.     double integer, tmp;
  676.  
  677.     dotrim = expcnt = gformat = 0;
  678.     if (number < 0) {
  679.         number = -number;
  680.         *signp = '-';
  681.     } else
  682.         *signp = 0;
  683.  
  684.     fract = modf(number, &integer);
  685.  
  686.     /* get an extra slot for rounding. */
  687.     t = ++startp;
  688.  
  689.     /*
  690.      * get integer portion of number; put into the end of the buffer; the
  691.      * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  692.      */
  693.     for (p = endp - 1; integer; ++expcnt) {
  694.         tmp = modf(integer / 10, &integer);
  695.         *p-- = to_char((int)((tmp + .01) * 10));
  696.     }
  697.     switch (fmtch) {
  698.     case 'f':
  699.         /* reverse integer into beginning of buffer */
  700.         if (expcnt)
  701.             for (; ++p < endp; *t++ = *p);
  702.         else
  703.             *t++ = '0';
  704.         /*
  705.          * if precision required or alternate flag set, add in a
  706.          * decimal point.
  707.          */
  708.         if (prec || flags&ALT)
  709.             *t++ = '.';
  710.         /* if requires more precision and some fraction left */
  711.         if (fract) {
  712.             if (prec)
  713.                 do {
  714.                     fract = modf(fract * 10, &tmp);
  715.                     *t++ = to_char((int)tmp);
  716.                 } while (--prec && fract);
  717.             if (fract)
  718.                 startp = round(fract, (int *)NULL, startp,
  719.                     t - 1, (char)0, signp);
  720.         }
  721.         for (; prec--; *t++ = '0');
  722.         break;
  723.     case 'e':
  724.     case 'E':
  725. eformat:    if (expcnt) {
  726.             *t++ = *++p;
  727.             if (prec || flags&ALT)
  728.                 *t++ = '.';
  729.             /* if requires more precision and some integer left */
  730.             for (; prec && ++p < endp; --prec)
  731.                 *t++ = *p;
  732.             /*
  733.              * if done precision and more of the integer component,
  734.              * round using it; adjust fract so we don't re-round
  735.              * later.
  736.              */
  737.             if (!prec && ++p < endp) {
  738.                 fract = 0;
  739.                 startp = round((double)0, &expcnt, startp,
  740.                     t - 1, *p, signp);
  741.             }
  742.             /* adjust expcnt for digit in front of decimal */
  743.             --expcnt;
  744.         }
  745.         /* until first fractional digit, decrement exponent */
  746.         else if (fract) {
  747.             /* adjust expcnt for digit in front of decimal */
  748.             for (expcnt = -1;; --expcnt) {
  749.                 fract = modf(fract * 10, &tmp);
  750.                 if (tmp)
  751.                     break;
  752.             }
  753.             *t++ = to_char((int)tmp);
  754.             if (prec || flags&ALT)
  755.                 *t++ = '.';
  756.         }
  757.         else {
  758.             *t++ = '0';
  759.             if (prec || flags&ALT)
  760.                 *t++ = '.';
  761.         }
  762.         /* if requires more precision and some fraction left */
  763.         if (fract) {
  764.             if (prec)
  765.                 do {
  766.                     fract = modf(fract * 10, &tmp);
  767.                     *t++ = to_char((int)tmp);
  768.                 } while (--prec && fract);
  769.             if (fract)
  770.                 startp = round(fract, &expcnt, startp,
  771.                     t - 1, (char)0, signp);
  772.         }
  773.         /* if requires more precision */
  774.         for (; prec--; *t++ = '0');
  775.  
  776.         /* unless alternate flag, trim any g/G format trailing 0's */
  777.         if (gformat && !(flags&ALT)) {
  778.             while (t > startp && *--t == '0');
  779.             if (*t == '.')
  780.                 --t;
  781.             ++t;
  782.         }
  783.         t = exponent(t, expcnt, fmtch);
  784.         break;
  785.     case 'g':
  786.     case 'G':
  787.         /* a precision of 0 is treated as a precision of 1. */
  788.         if (!prec)
  789.             ++prec;
  790.         /*
  791.          * ``The style used depends on the value converted; style e
  792.          * will be used only if the exponent resulting from the
  793.          * conversion is less than -4 or greater than the precision.''
  794.          *    -- ANSI X3J11
  795.          */
  796.         if (expcnt > prec || (!expcnt && fract && fract < .0001)) {
  797.             /*
  798.              * g/G format counts "significant digits, not digits of
  799.              * precision; for the e/E format, this just causes an
  800.              * off-by-one problem, i.e. g/G considers the digit
  801.              * before the decimal point significant and e/E doesn't
  802.              * count it as precision.
  803.              */
  804.             --prec;
  805.             fmtch -= 2;        /* G->E, g->e */
  806.             gformat = 1;
  807.             goto eformat;
  808.         }
  809.         /*
  810.          * reverse integer into beginning of buffer,
  811.          * note, decrement precision
  812.          */
  813.         if (expcnt)
  814.             for (; ++p < endp; *t++ = *p, --prec);
  815.         else
  816.             *t++ = '0';
  817.         /*
  818.          * if precision required or alternate flag set, add in a
  819.          * decimal point.  If no digits yet, add in leading 0.
  820.          */
  821.         if (prec || flags&ALT) {
  822.             dotrim = 1;
  823.             *t++ = '.';
  824.         }
  825.         else
  826.             dotrim = 0;
  827.         /* if requires more precision and some fraction left */
  828.         if (fract) {
  829.             if (prec) {
  830.                 do {
  831.                     fract = modf(fract * 10, &tmp);
  832.                     *t++ = to_char((int)tmp);
  833.                 } while(!tmp);
  834.                 while (--prec && fract) {
  835.                     fract = modf(fract * 10, &tmp);
  836.                     *t++ = to_char((int)tmp);
  837.                 }
  838.             }
  839.             if (fract)
  840.                 startp = round(fract, (int *)NULL, startp,
  841.                     t - 1, (char)0, signp);
  842.         }
  843.         /* alternate format, adds 0's for precision, else trim 0's */
  844.         if (flags&ALT)
  845.             for (; prec--; *t++ = '0');
  846.         else if (dotrim) {
  847.             while (t > startp && *--t == '0');
  848.             if (*t != '.')
  849.                 ++t;
  850.         }
  851.     }
  852.     return (t - startp);
  853. }
  854.  
  855. #endif /* FLOATING_POINT */
  856.  
  857. int __sbprintf(streambuf *sb, const char* format, ...)
  858. {
  859.     va_list args;
  860.     va_start(args, format);
  861.     int ret = __vsbprintf(sb, format, args);
  862.     va_end(args);
  863.     return ret;
  864. }
  865.